package org.luo.lan.common.config;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.luo.lan.common.Constant;
import org.luo.lan.common.util.Assert;
import org.luo.lan.common.util.Pair;
import org.luo.lan.common.util.WatchServiceUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
 * @Auther: luobiao
 * @Date: 2020/9/19 09:15
 * @Description:
 */
@Slf4j
public abstract class AbstractConfig<T> implements Config {
    protected T config;
    protected String configFileName;
    protected Class<T> configInfoClass;



    @Override
    public T init() {
        config=readFileAndParse();
        Pair<Boolean,String> pair = checkConfig(config);
        if(!pair.getKey()){
            log.error(pair.getValue());
            throw new RuntimeException("配置校验异常！");
        }
        WatchServiceUtil.watchDirChange(Constant.USER_DIR,(changeFileList)->{
            if(changeFileList.contains(configFileName)){
                onChange();
            }
        });
        return config;
    }

    private T readFileAndParse(){
        String filePath = Constant.USER_DIR + configFileName;
        File file = new File(filePath);
        Assert.fielExist(file, "初始化配置出错，配置文件不存在！userDir=%s；filePath=%s", Constant.USER_DIR, filePath);
        T config=null;
        try (InputStream inputStream = new FileInputStream(file)){
            config=JSON.parseObject(inputStream, configInfoClass);
        } catch (IOException ex) {
            log.info("配置初始化异常：{}",ex);
        }
        return config;
    }

    @Override
    public void onChange() {
        log.info("配置文件发生改变！");
        T newConfig=readFileAndParse();
        Pair<Boolean,String> pair = checkConfig(newConfig);
        if(!pair.getKey()){
            log.error(pair.getValue());
            return;
        }
        //此处需要加锁，防止其他线程正在使用配置
        synchronized (this) {
            this.config=newConfig;
            doUpdate();
        }
    }

    /**
     * 在配置发生变化时，留给子类扩展的接口
     */
    protected  void doUpdate(){}
    protected  abstract Pair<Boolean,String> checkConfig(T t);


}
